﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using StripeOne.Core.S1Exceptions;
using System.Xml;

namespace StripeOne.Core.S1Config
{
    internal static class S1ConfigLoader
    {
        private class S1ConfigFile
        {
            public Dictionary<string, S1ConfigLoader.S1ConfigSection> Sections { get; set; }
        }
        private class S1ConfigSection
        {
            public Dictionary<string, string> Values { get; set; }
        }
        private class S1AdditionalConfig
        {
            public string File { get; set; }
            public string Section { get; set; }
            public string Setting { get; set; }
            public string Value { get; set; }
        }
        private class S1AdditionalFolder
        {
            public string Folder { get; set; }
            public bool HasPriority { get; set; }
        }
        private static object _syncRoot = new object();
        private static Dictionary<string, S1ConfigLoader.S1ConfigFile> _storage = null;
        private static Dictionary<string, FileSystemWatcher> _watchers = new Dictionary<string, FileSystemWatcher>();
        private static List<S1ConfigLoader.S1AdditionalFolder> _additionalFolders = new List<S1ConfigLoader.S1AdditionalFolder>();
        private static List<string> _additionalFiles = new List<string>();
        private static List<S1ConfigLoader.S1AdditionalConfig> _additionalConfig = new List<S1ConfigLoader.S1AdditionalConfig>();
        private static List<string> _optionalFiles = new List<string>();
        private static void Init()
        {
            if (S1ConfigLoader._storage != null)
            {
                return;
            }
            Monitor.Enter(S1ConfigLoader._syncRoot);
            try
            {
                if (S1ConfigLoader._storage == null)
                {
                    string[] array = new string[]
					{
						".xml",
						".s1config"
					};
                    bool flag = S1ConfigLoader._additionalFolders.Count > 0 || S1ConfigLoader._additionalFiles.Count > 0 || S1ConfigLoader._additionalConfig.Count > 0;
                    string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config\\");
                    bool flag2 = flag && !Directory.Exists(text);
                    List<string> list = new List<string>();
                    list.AddRange((
                        from f in S1ConfigLoader._additionalFolders
                        where !f.HasPriority
                        select f.Folder).ToArray<string>());
                    if (!flag2)
                    {
                        list.Add(text);
                    }
                    list.AddRange((
                        from f in S1ConfigLoader._additionalFolders
                        where f.HasPriority
                        select f.Folder).ToArray<string>());
                    List<string> list2 = new List<string>();
                    List<string> list3 = new List<string>();
                    Dictionary<string, S1ConfigLoader.S1ConfigFile> dictionary = new Dictionary<string, S1ConfigLoader.S1ConfigFile>();
                    foreach (S1ConfigLoader.S1AdditionalConfig current in S1ConfigLoader._additionalConfig)
                    {
                        S1ConfigLoader.StoreConfig(dictionary, current.File, string.Empty, current.Section, current.Setting, current.Value);
                    }
                    foreach (string current2 in list)
                    {
                        string[] array2 = array;
                        for (int i = 0; i < array2.Length; i++)
                        {
                            string str = array2[i];
                            string[] files = Directory.GetFiles(current2, "*" + str, SearchOption.AllDirectories);
                            string[] array3 = files;
                            for (int j = 0; j < array3.Length; j++)
                            {
                                string item = array3[j];
                                list2.Add(item);
                                list3.Add(current2);
                            }
                        }
                    }
                    foreach (string current3 in S1ConfigLoader._additionalFiles)
                    {
                        list2.Add(current3);
                        list3.Add(Path.GetDirectoryName(current3));
                    }
                    for (int k = 0; k < list2.Count; k++)
                    {
                        S1ConfigLoader.LoadFile(dictionary, list2[k], list3[k]);
                    }
                    foreach (S1ConfigLoader.S1AdditionalConfig current4 in S1ConfigLoader._additionalConfig)
                    {
                        S1ConfigLoader.StoreConfig(dictionary, current4.File, string.Empty, current4.Section, current4.Setting, current4.Value);
                    }
                    foreach (string current5 in S1ConfigLoader._optionalFiles)
                    {
                        string key = Path.GetFileNameWithoutExtension(current5).ToLower();
                        if (!dictionary.ContainsKey(key))
                        {
                            dictionary[key] = new S1ConfigLoader.S1ConfigFile();
                            dictionary[key].Sections = new Dictionary<string, S1ConfigLoader.S1ConfigSection>();
                        }
                    }
                    string[] array4 = (
                        from kvp in dictionary
                        select kvp.Key).ToArray<string>();
                    string[] array5 = array4;
                    for (int l = 0; l < array5.Length; l++)
                    {
                        string text2 = array5[l];
                        string[] array6 = array;
                        for (int m = 0; m < array6.Length; m++)
                        {
                            string str2 = array6[m];
                            dictionary[text2 + str2] = dictionary[text2];
                        }
                    }
                    foreach (string current6 in list2)
                    {
                        S1ConfigLoader.AddWatcher(Path.GetDirectoryName(current6));
                    }
                    if (dictionary.Count > 0)
                    {
                        S1ConfigLoader._storage = dictionary;
                    }
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                Monitor.Exit(S1ConfigLoader._syncRoot);
            }
        }
        private static void ValidateFile(string fileKey)
        {
            if (Path.IsPathRooted(fileKey))
            {
                throw new S1ConfigException("Attempted to load a configuration file using '" + fileKey + "'. Configuration classes must use only the file name.", null);
            }
            if (S1ConfigLoader._storage != null && S1ConfigLoader._storage.ContainsKey(fileKey))
            {
                return;
            }
            if (S1ConfigLoader._watchers.Count > 0)
            {
                string text = string.Join(Environment.NewLine, (
                    from w in S1ConfigLoader._watchers
                    select w.Value.Path).ToArray<string>());
                throw new S1ConfigException(string.Concat(new string[]
				{
					"Could not locate configuration file '",
					fileKey,
					"'. Searched locations: ",
					Environment.NewLine,
					text
				}), null);
            }
            throw new S1ConfigException("Could not locate configuration file '" + fileKey + ".'", null);
        }
        private static void LoadFile(Dictionary<string, S1ConfigLoader.S1ConfigFile> storage, string file, string baseFolder)
        {
            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(file);
                S1ConfigLoader.StoreConfig(storage, file, baseFolder, string.Empty, string.Empty, string.Empty);
                foreach (XmlNode xmlNode in xmlDocument.DocumentElement.ChildNodes)
                {
                    if (xmlNode is XmlElement)
                    {
                        foreach (XmlNode xmlNode2 in xmlNode.ChildNodes)
                        {
                            if (xmlNode2 is XmlElement)
                            {
                                string value = string.Empty;
                                XmlNode xmlNode3 = xmlNode2.SelectSingleNode("text()");
                                if (xmlNode3 != null)
                                {
                                    value = xmlNode3.Value.ToString();
                                }
                                S1ConfigLoader.StoreConfig(storage, file, baseFolder, xmlNode.Name, xmlNode2.Name, value);
                            }
                        }
                    }
                }
            }
            catch (Exception innerException)
            {
                throw new S1ConfigException("Error loading configuration file \"" + file + "\"", innerException);
            }
        }
        private static void StoreConfig(Dictionary<string, S1ConfigLoader.S1ConfigFile> storage, string file, string baseFolder, string section, string setting, string value)
        {
            string text = Path.GetFileNameWithoutExtension(file).ToLower();
            if (baseFolder.Length > 0)
            {
                string text2 = Path.GetDirectoryName(file);
                if (!baseFolder.EndsWith("\\"))
                {
                    baseFolder += "\\";
                }
                if (!text2.EndsWith("\\"))
                {
                    text2 += "\\";
                }
                if (text2.Length > baseFolder.Length)
                {
                    string text3 = text2.Substring(baseFolder.Length);
                    text = text3.ToLower() + text;
                }
            }
            string text4 = section.ToLower();
            string text5 = setting.ToLower();
            if (!storage.ContainsKey(text))
            {
                storage[text] = new S1ConfigLoader.S1ConfigFile();
                storage[text].Sections = new Dictionary<string, S1ConfigLoader.S1ConfigSection>();
            }
            if (text4.Length > 0 && !storage[text].Sections.ContainsKey(text4))
            {
                storage[text].Sections[text4] = new S1ConfigLoader.S1ConfigSection();
                storage[text].Sections[text4].Values = new Dictionary<string, string>();
            }
            if (text5.Length > 0 && value.Length > 0)
            {
                storage[text].Sections[text4].Values[text5] = value;
            }
        }
        private static void AddWatcher(string folder)
        {
            string key = folder.ToLower();
            FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
            if (!S1ConfigLoader._watchers.ContainsKey(key))
            {
                fileSystemWatcher.Path = folder;
                fileSystemWatcher.NotifyFilter = (NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite);
                fileSystemWatcher.Filter = "*.*";
                fileSystemWatcher.Changed += delegate(object s, FileSystemEventArgs e)
                {
                    S1ConfigLoader.ClearCache();
                }
                ;
                fileSystemWatcher.Created += delegate(object s, FileSystemEventArgs e)
                {
                    S1ConfigLoader.ClearCache();
                }
                ;
                fileSystemWatcher.Deleted += delegate(object s, FileSystemEventArgs e)
                {
                    S1ConfigLoader.ClearCache();
                }
                ;
                fileSystemWatcher.Renamed += delegate(object s, RenamedEventArgs e)
                {
                    S1ConfigLoader.ClearCache();
                }
                ;
                fileSystemWatcher.EnableRaisingEvents = true;
                S1ConfigLoader._watchers.Add(key, fileSystemWatcher);
            }
        }
        internal static void ClearCache()
        {
            S1ConfigLoader._storage = null;
        }
        internal static void AddConfigurationPath(string configPath, bool hasPriority)
        {
            if (!S1ConfigLoader._additionalFolders.Any((S1ConfigLoader.S1AdditionalFolder f) => f.Folder.Equals(configPath, StringComparison.InvariantCultureIgnoreCase)))
            {
                S1ConfigLoader._additionalFolders.Add(new S1ConfigLoader.S1AdditionalFolder
                {
                    Folder = configPath,
                    HasPriority = hasPriority
                });
                S1ConfigLoader.ClearCache();
            }
        }
        internal static void AddConfigurationFile(string configFile)
        {
            if (!S1ConfigLoader._additionalFiles.Contains(configFile.ToLower()))
            {
                S1ConfigLoader._additionalFiles.Add(configFile.ToLower());
                S1ConfigLoader.ClearCache();
            }
        }
        internal static void AddConfigurationSetting(string file, string section, string setting, string value)
        {
            if (section == null || section.Length == 0)
            {
                section = "default";
            }
            S1ConfigLoader._additionalConfig.Add(new S1ConfigLoader.S1AdditionalConfig
            {
                File = file,
                Section = section,
                Setting = setting,
                Value = value
            });
            S1ConfigLoader.ClearCache();
        }
        internal static void AddOptionalFile(string configFile)
        {
            if (!S1ConfigLoader._optionalFiles.Contains(configFile.ToLower()))
            {
                S1ConfigLoader._optionalFiles.Add(configFile.ToLower());
                S1ConfigLoader.ClearCache();
            }
        }
        internal static string GetValue(string file, string section, string setting)
        {
            S1ConfigLoader.Init();
            string text = file.ToLower();
            string key = section.ToLower();
            string key2 = setting.ToLower();
            S1ConfigLoader.ValidateFile(text);
            if (S1ConfigLoader._storage == null || !S1ConfigLoader._storage.ContainsKey(text))
            {
                return string.Empty;
            }
            if (!S1ConfigLoader._storage[text].Sections.ContainsKey(key))
            {
                return string.Empty;
            }
            if (!S1ConfigLoader._storage[text].Sections[key].Values.ContainsKey(key2))
            {
                return string.Empty;
            }
            return S1ConfigLoader._storage[text].Sections[key].Values[key2];
        }
        internal static string[] GetConfigurationPaths()
        {
            List<string> list = new List<string>();
            list.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config\\"));
            list.AddRange((
                from f in S1ConfigLoader._additionalFolders
                select f.Folder).ToArray<string>());
            return list.ToArray();
        }
        internal static string[] GetFiles()
        {
            S1ConfigLoader.Init();
            List<string> list = new List<string>();
            foreach (KeyValuePair<string, S1ConfigLoader.S1ConfigFile> current in S1ConfigLoader._storage)
            {
                if (current.Key.ToLower().EndsWith(".SoConfig"))
                {
                    list.Add(current.Key);
                }
            }
            return list.ToArray();
        }
        internal static string[] GetSections(string file)
        {
            S1ConfigLoader.Init();
            string text = file.ToLower();
            S1ConfigLoader.ValidateFile(text);
            List<string> list = new List<string>();
            foreach (KeyValuePair<string, S1ConfigLoader.S1ConfigSection> current in S1ConfigLoader._storage[text].Sections)
            {
                list.Add(current.Key);
            }
            return list.ToArray();
        }
        internal static string[] GetKeys(string file, string section)
        {
            S1ConfigLoader.Init();
            if (Path.IsPathRooted(file))
            {
                throw new S1ConfigException("Attempted to load a configuration file using '" + file + "'. Configuration files must use relative paths.", null);
            }
            string text = file.ToLower();
            string key = section.ToLower();
            S1ConfigLoader.ValidateFile(text);
            if (!S1ConfigLoader._storage[text].Sections.ContainsKey(key))
            {
                return new string[0];
            }
            List<string> list = new List<string>();
            foreach (KeyValuePair<string, string> current in S1ConfigLoader._storage[text].Sections[key].Values)
            {
                list.Add(current.Key);
            }
            return list.ToArray();
        }
    }
}
